package cn.janescott.framework.core.json.deserializer;

import cn.janescott.framework.core.exception.MyException;
import cn.janescott.framework.core.json.serializer.MyExceptionSerializer;
import cn.janescott.framework.core.utils.LoggerUtils;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonNode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

/**
 * 自定义异常 反序列化
 *
 * @author scott
 * @date 2019/2/25
 */
public class MyExceptionDeserializer extends JsonDeserializer<MyException> {

    private Logger logger = LoggerFactory.getLogger(getClass());

    @Override
    public MyException deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JsonProcessingException {
        JsonNode node = jsonParser.getCodec().readTree(jsonParser);
        String errorCode = null;
        if (!node.get(MyExceptionSerializer.ERROR_CODE).isNull()) {
            errorCode = node.get(MyExceptionSerializer.ERROR_CODE).asText();
        }
        String errorMessage = null;
        if (!node.get(MyExceptionSerializer.ERROR_MESSAGE).isNull()) {
            errorMessage = node.get(MyExceptionSerializer.ERROR_MESSAGE).asText();
        }
        String className = null;
        if (!node.get(MyExceptionSerializer.CLASS_NAME).isNull()) {
            className = node.get(MyExceptionSerializer.CLASS_NAME).asText();
        }
        /* 尝试生成实际类型的异常，如果失败，则直接生成MyException异常 */
        if (className != null && !(className.trim().isEmpty())) {
            try {
                Class<?> forName = Class.forName(className);
                Constructor<?> constructor = forName.getDeclaredConstructor(String.class, String.class, Throwable.class);
                constructor.setAccessible(true);
                return (MyException) constructor.newInstance(errorCode, errorMessage, null);
            } catch (InstantiationException | InvocationTargetException | NoSuchMethodException | IllegalAccessException | ClassNotFoundException e) {
                LoggerUtils.error(logger, () -> e);
            }
        }
        return new MyException(errorCode, errorMessage);
    }
}
